package com.gupao.dubbo.netty.client.proxy;

import com.gupao.dubbo.netty.RpcRquest;
import com.gupao.dubbo.netty.server.RpcHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class RpcProxy {
    static final RpcProxyHandler rpcProxyHandler = new RpcProxyHandler();

    public static <T> T create(Class<T> interfaceClass, final String serviceAddress) {
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{interfaceClass}, new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                NioEventLoopGroup group = new NioEventLoopGroup();
                try {
                    Bootstrap bootstrap = new Bootstrap().group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pip = ch.pipeline();
                            pip.addLast("frameDecodeer", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                            pip.addLast("frameEncode", new LengthFieldPrepender(4));
                            pip.addLast("encode", new ObjectEncoder());
                            pip.addLast("decoder", new ObjectDecoder(ClassResolvers.cacheDisabled(Thread.currentThread().getContextClassLoader())));
                            pip.addLast(rpcProxyHandler);
                        }
                    });
                    bootstrap.option(ChannelOption.TCP_NODELAY, true);
                    String[] split = serviceAddress.split(":");
                    String ip = split[0];
                    int port = Integer.valueOf(split[1]);
                    Channel channel = bootstrap.connect(ip, port).sync().channel();

                    RpcRquest rpcRquest = new RpcRquest(method.getDeclaringClass().getName(), method.getName(), method.getParameterTypes(), args);
                    channel.writeAndFlush(rpcRquest);
                    channel.closeFuture().sync();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    group.shutdownGracefully();
                }
                return rpcProxyHandler.getResponse();
            }
        });
    }
}
